/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * RulesPanel.java
 *
 * Created on May 22, 2009, 11:45:02 PM
 */
package view.panels.rules;

import controller.GraphController;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.TreeMap;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.SpinnerNumberModel;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import jgf.Attribute;
import jgf.beans.ArcBean;
import jgf.beans.GraphBean;
import jgf.beans.NodeBean;
import utils.JGSCommonTools;
import view.panels.JGSPanel;

/**
 *
 * @author Biddu
 */
public class RulesPanel extends JGSPanel {

	/** Creates new form RulesPanel */
	public RulesPanel() {
		initComponents();
	}

	/** This method is called from within the constructor to
	 * initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is
	 * always regenerated by the Form Editor.
	 */
	@SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        panelNodeTools = new javax.swing.JPanel();
        labelNodeAttributes = new javax.swing.JLabel();
        spinnerNode = new javax.swing.JSpinner();
        scrollTableNode = new javax.swing.JScrollPane();
        tableNode = new javax.swing.JTable();
        panelArcTools = new javax.swing.JPanel();
        labelArcAttributes = new javax.swing.JLabel();
        spinnerArc = new javax.swing.JSpinner();
        scrollTableArc = new javax.swing.JScrollPane();
        tableArc = new javax.swing.JTable();

        setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS));

        panelNodeTools.setLayout(new java.awt.BorderLayout());

        labelNodeAttributes.setText("Node Attributes");
        panelNodeTools.add(labelNodeAttributes, java.awt.BorderLayout.LINE_START);
        panelNodeTools.add(spinnerNode, java.awt.BorderLayout.EAST);

        add(panelNodeTools);

        tableNode.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "*", "Attribute Name", "Default Value", "Delete"
            }
        ));
        scrollTableNode.setViewportView(tableNode);

        add(scrollTableNode);

        panelArcTools.setLayout(new java.awt.BorderLayout());

        labelArcAttributes.setText("Arc Attributes");
        panelArcTools.add(labelArcAttributes, java.awt.BorderLayout.CENTER);
        panelArcTools.add(spinnerArc, java.awt.BorderLayout.EAST);

        add(panelArcTools);

        tableArc.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "*", "Attribute Name", "Default Value", "Delete"
            }
        ) {
            boolean[] canEdit = new boolean [] {
                false, true, true, true
            };

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        scrollTableArc.setViewportView(tableArc);

        add(scrollTableArc);
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel labelArcAttributes;
    private javax.swing.JLabel labelNodeAttributes;
    private javax.swing.JPanel panelArcTools;
    private javax.swing.JPanel panelNodeTools;
    private javax.swing.JScrollPane scrollTableArc;
    private javax.swing.JScrollPane scrollTableNode;
    private javax.swing.JSpinner spinnerArc;
    private javax.swing.JSpinner spinnerNode;
    private javax.swing.JTable tableArc;
    private javax.swing.JTable tableNode;
    // End of variables declaration//GEN-END:variables
	// <editor-fold defaultstate="collapsed" desc="Custom Code">
	private GraphBean graph;
	private int selectedRowID;
	private int nrowcount = 0;
	private int arowcount = 0;
	private int ncounter = 1;
	private int acounter = 1;
	private String default_AttrName = "Attribute_";
	private Integer default_AttrValue = 1;
	private javax.swing.table.DefaultTableModel nodeModel;
	private javax.swing.table.DefaultTableModel arcModel;
	private TreeMap<Integer, String> nodeAttrRows;
	private TreeMap<Integer, String> arcAttrRows;
	private static int NODE_ID = 1;
	private static int ARC_ID = 2;
	private boolean deleteAttribute = false;
	private GraphController gc;// FIXME The use of the GraphController should be dynamic to save memory.

	public void loadGraph(GraphBean graph) {
		this.graph = graph;
		commonCodeOnLoad();
		//lets add Listeners to the components
		addListeners();
		syncOnLoad();
	}

	/**
	 *
	 */
	private void commonCodeOnLoad() {
		nodeAttrRows = new TreeMap<Integer, String>();
		arcAttrRows = new TreeMap<Integer, String>();
		nodeModel = (javax.swing.table.DefaultTableModel) tableNode.getModel();
		arcModel = (javax.swing.table.DefaultTableModel) tableArc.getModel();
		gc = controller.getGraphController(graph.getID());
	}

	/**
	After loading the graph to the
	Panel lets add listeners to the various
	components of the graph
	 */
	private void addListeners() {

		int vColIndex = 3;//Delete Column
		TableColumn tcoln3 = tableNode.getColumnModel().getColumn(vColIndex);
		tcoln3.setCellRenderer(new ButtonTableRenderer());
		tcoln3.setCellEditor(new ButtonTableEditor(new JCheckBox(), NODE_ID));

		TableColumn tcola3 = tableArc.getColumnModel().getColumn(vColIndex);
		tcola3.setCellRenderer(new ButtonTableRenderer());
		tcola3.setCellEditor(new ButtonTableEditor(new JCheckBox(), ARC_ID));

		tableNode.getModel().addTableModelListener(new TableModelListener() {

			public void tableChanged(TableModelEvent e) {
				int row = e.getFirstRow();
				int column = e.getColumn();
				selectedRowID = row;
				TableModel model = (TableModel) e.getSource();
				if (row >= 0 && column == 1) {
					String changedValue = model.getValueAt(row, column).toString();
					if (!nodeAttrRows.get(row).equalsIgnoreCase(changedValue)) {
						gc.updateNodeAttribute(nodeAttrRows.get(row), changedValue, 1);
					}
				}
				if (row >= 0 && column == 2) {
					String changedValue = model.getValueAt(row, column).toString();
					if (JGSCommonTools.containsOnlyNumbers(changedValue)) {
						gc.updateNodeAttribute(nodeAttrRows.get(row), nodeAttrRows.get(row), Integer.parseInt(changedValue));
					} else {
						JOptionPane.showMessageDialog(tableArc, "Please verify the entered value is Numeic");
					}
				}
			}
		});

		tableArc.getModel().addTableModelListener(new TableModelListener() {

			public void tableChanged(TableModelEvent e) {
				int row = e.getFirstRow();
				int column = e.getColumn();
				selectedRowID = row;
				TableModel model = (TableModel) e.getSource();
				if (row >= 0 && column == 1) {
					String changedValue = model.getValueAt(row, column).toString();
					if (!arcAttrRows.get(row).equalsIgnoreCase(changedValue)) {
						gc.updateArcAttribute(arcAttrRows.get(row), changedValue, 1);
					}
				}
				if (row >= 0 && column == 2) {
					String changedValue = model.getValueAt(row, column).toString();
					if (JGSCommonTools.containsOnlyNumbers(changedValue)) {
						gc.updateArcAttribute(arcAttrRows.get(row), arcAttrRows.get(row), Integer.parseInt(changedValue));
					} else {
						JOptionPane.showMessageDialog(tableArc, "Please verify the entered value is Numeic");
					}
				}
			}
		});

		spinnerNode.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1));
		spinnerNode.addChangeListener(new SpinnerListener());
		spinnerArc.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1));
		spinnerArc.addChangeListener(new SpinnerListener());
	}

	private void syncOnLoad() {
		if (graph != null && graph.getNodeList().size() > 0) {
			for (Attribute atr : graph.getNodeList().firstElement().getAttributes()) {
				this.addNodeAttribute(atr.getName(), atr.getValue());
			}
		}
		if (graph != null && graph.getArcList().size() > 0) {
			for (Attribute atr : graph.getArcList().firstElement().getAttributes()) {
				this.addArcAttribute(atr.getName(), atr.getValue());
			}
		}
	}

	@Override
	public void deleteArc(ArcBean arc) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	@Override
	public void deleteNode(NodeBean node) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	@Override
	public void insertArc(ArcBean arc) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	@Override
	public void insertNode(NodeBean node) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	@Override
	public void setSink(NodeBean sink) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	@Override
	public void setSource(NodeBean source) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	@Override
	public void unsetSink(NodeBean sink) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	@Override
	public void unsetSource(NodeBean source) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	@Override
	public void updateArc(ArcBean arc) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	@Override
	public void updateNode(NodeBean node) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	public void setGraphName(String name) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	/**
	 * Below implements the Spinner behaviour we want
	 */
	private class SpinnerListener implements ChangeListener {

		public void stateChanged(ChangeEvent evt) {
			JSpinner spinner = (JSpinner) evt.getSource();
			// Get the new value
			Object value = spinner.getValue();
			int noOfRows = (Integer) value;
			if (spinnerNode == spinner) {
				if (noOfRows > nrowcount) {
					for (int r = nrowcount; r < noOfRows; r++) {
						String name = default_AttrName + ncounter;
						ncounter++;
						Integer val = default_AttrValue;
						gc.addDefaultNodeAttribute(new Attribute(name, val));
					}
				} else if (noOfRows < nrowcount) {
					for (int r = nrowcount; r > noOfRows; r--) {
						gc.removeDefaultNodeAttribute(nodeAttrRows.get(r - 1));
					}
				}
			} else if (spinnerArc == spinner) {
				if (noOfRows > arowcount) {
					for (int a = arowcount; a < noOfRows; a++) {
						String name = default_AttrName + acounter;
						acounter++;
						Integer val = default_AttrValue;
						gc.addArcAttribute(name, val);
					}
				} else if (noOfRows < arowcount && noOfRows > -1) {
					for (int a = arowcount; a > noOfRows; a--) {
						gc.removeArcAttribute(arcAttrRows.get(a - 1));
					}
				}
			}
		}
	}

	public void addNodeAttribute(String name, Integer defaultValue) {
		nodeModel.insertRow(nrowcount, new Object[]{"" + (nrowcount + 1), name, defaultValue, "X"});
		nodeAttrRows.put(nrowcount, name);
		nrowcount++;
		spinnerNode.setValue(new Integer(nrowcount));
	}

	public void removeNodeAttribute(String name) {
		if (!deleteAttribute) {
			for (int n = 0; n < nodeAttrRows.size(); n++) {
				if (name.equals(nodeAttrRows.get(n))) {
					nodeModel.removeRow(n);
					nodeAttrRows.remove(n);
					nrowcount--;
				}
			}
		}
	}

	public void addArcAttribute(String name, Integer defaultValue) {
		arcModel.insertRow(arowcount, new Object[]{"" + (arowcount + 1), name, defaultValue, "X"});
		arcAttrRows.put(arowcount, name);
		arowcount++;
		spinnerArc.setValue(new Integer(arowcount));
	}

	public void removeArcAttribute(String name) {
		if (!deleteAttribute) {
			for (int a = 0; a < arcAttrRows.size(); a++) {
				if (name.equalsIgnoreCase(arcAttrRows.get(a))) {
					arcModel.removeRow(a);
					arcAttrRows.remove(a);
					arowcount--;
				}
			}
		}
	}

	private void deleteAttribute(int selectedRowID, int callerID) {
		TreeMap<Integer, String> tempNodes = new TreeMap<Integer, String>();
		Integer tempRowCount = 0;
		if (callerID == NODE_ID) {
			nodeModel.removeRow(selectedRowID);
			for (int i = 0; i < nrowcount; i++) {
				if (i != selectedRowID) {
					tempNodes.put(tempRowCount, nodeAttrRows.get(i));
					nodeModel.setValueAt(tempRowCount + 1, tempRowCount, 0);
					tempRowCount++;
				}
			}
			nodeAttrRows = tempNodes;
			nrowcount--;
			spinnerNode.setValue(new Integer(nrowcount));
		} else if (callerID == ARC_ID) {
			arcModel.removeRow(selectedRowID);
			for (int i = 0; i < arowcount; i++) {
				if (i != selectedRowID) {
					tempNodes.put(tempRowCount, arcAttrRows.get(i));
					arcModel.setValueAt(tempRowCount + 1, tempRowCount, 0);
					tempRowCount++;
				}
			}
			arcAttrRows = tempNodes;
			arowcount--;
			spinnerArc.setValue(new Integer(arowcount));
		}
	}

	public void updateArcAttribute(String previousName, String newName, Integer newValue) {
		TreeMap<Integer, String> tempArcs = new TreeMap<Integer, String>();
		Integer tempRowCount = 0;
		for (int i = 0; i < arowcount; i++) {
			if (i != selectedRowID) {
				tempArcs.put(tempRowCount, arcAttrRows.get(i));
			} else {
				tempArcs.put(tempRowCount, newName);
			}
			tempRowCount++;
		}
		arcAttrRows = tempArcs;
		arcModel.setValueAt(newName, selectedRowID, 1);
	}

	public void updateNodeAttribute(String previousName, String newName, Integer newValue) {
		TreeMap<Integer, String> tempNodes = new TreeMap<Integer, String>();
		Integer tempRowCount = 0;
		for (int i = 0; i < nrowcount; i++) {
			if (i != selectedRowID) {
				tempNodes.put(tempRowCount, nodeAttrRows.get(i));
			} else {
				tempNodes.put(tempRowCount, newName);
			}
			tempRowCount++;
		}
		nodeAttrRows = tempNodes;
		nodeModel.setValueAt(newName, selectedRowID, 1);
	}

	/**
	 * Below 2 classes implements the Button in the
	 * delete column of the
	 * node and arc tables.
	 */
	private class ButtonTableRenderer extends JButton implements TableCellRenderer {

		public ButtonTableRenderer() {
			setOpaque(true);
		}

		public Component getTableCellRendererComponent(JTable table, Object value,
				boolean isSelected, boolean hasFocus, int row, int column) {
			if (isSelected) {
				setForeground(table.getSelectionForeground());
				setBackground(table.getSelectionBackground());
			} else {
				setForeground(table.getForeground());
				setBackground(UIManager.getColor("Button.background"));
			}
			setText((value == null) ? "" : value.toString());
			return this;
		}
	}

	/**
	 * @version 1.0 11/09/98
	 */
	private class ButtonTableEditor extends DefaultCellEditor {

		protected JButton button;
		private String label;
		private boolean isPushed;
		private int buttonID;

		public ButtonTableEditor(JCheckBox checkBox, int id) {
			super(checkBox);
			button = new JButton();
			button.setOpaque(true);
			buttonID = id;
			button.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent e) {
					fireEditingStopped();
				}
			});
		}

		public void setButtonId(int id) {
			buttonID = id;
		}

		@Override
		public Component getTableCellEditorComponent(JTable table, Object value,
				boolean isSelected, int row, int column) {


			if (isSelected) {
				button.setForeground(table.getSelectionForeground());
				button.setBackground(table.getSelectionBackground());
			} else {
				button.setForeground(table.getForeground());
				button.setBackground(table.getBackground());
			}
			label = (value == null) ? "" : value.toString();
			button.setText(label);
			isPushed = true;
			selectedRowID = row;
			return button;
		}

		@Override
		public Object getCellEditorValue() {
			if (isPushed) {
				//
				if (buttonID == NODE_ID) {
					deleteAttribute = true;
					gc.removeNodeAttribute(nodeAttrRows.get(selectedRowID));
					deleteAttribute(selectedRowID, NODE_ID);
					deleteAttribute = false;
				} else if (buttonID == ARC_ID) {
					deleteAttribute = true;
					gc.removeArcAttribute(arcAttrRows.get(selectedRowID));
					deleteAttribute(selectedRowID, ARC_ID);
					deleteAttribute = false;
				}
			}
			//
			isPushed = false;
			return new String(label);
		}

		@Override
		public boolean stopCellEditing() {
			isPushed = false;
			return super.stopCellEditing();
		}

		@Override
		protected void fireEditingStopped() {
			try {
				super.fireEditingStopped();
			} catch (Exception e) {
			}
		}
	}
	// </editor-fold>

	@SuppressWarnings("static-access")
	public static void main(String s[]) {
		JFrame test = new JFrame();
		RulesPanel rules = new RulesPanel();
		test.add(rules);
		test.setVisible(true);

	}
}
